#ifndef MODBUSWND_H
#define MODBUSWND_H

#include <QWidget>
#include <QSerialPortInfo>
#include <serialport.h>
#include <QDateTime>
#include <QSettings>
#include <QStandardItemModel>
#include <QFile>
#include <QDir>
#include <QMessageBox>
#include <QFileDialog>
#include <QTimer>


namespace MODBUS_WND_TXRX_RESULT_COLUMNS
{
    enum {
        TIMESTAMP           ,
        STATUS              ,
        MODE                ,
        RAWDATA             ,
        CRC                 ,
        SLAVE_ADDR          ,
        FUNCTION            ,
        INFO                ,
        COUNT
    };
}
namespace MODBUS_WND_TX_QUEUE_COLUMNS
{
    enum {
        ENABLE           ,
        HEX              ,
        ASCII           ,
        COMMENT          ,
        COUNT
    };
}



namespace Ui {
class ModbusWnd;
}

class ModbusWnd : public QWidget
{
    Q_OBJECT

public:
    explicit ModbusWnd(QWidget *parent = 0);
    ~ModbusWnd();
    static bool check_ModbusRTU_CRC16(QByteArray buf, quint16 &result); //检查ModebusRTU帧CRC校验是否正确
    static quint16 ModbusRTU_CRC16 (const char *buf, quint16 wLength);  //根据const char *buf传来的信息，算出对应crc值
    static quint8 WEDM_sum(QByteArray buf); //线切割WEDM协议，我们不采用CRC校验而是和校验
    static quint8 WEDM_xor(QByteArray buf); //和异或校验
    static QByteArray toHexString(QByteArray buf);  //QByteArray数据类型转十六进制字符串

    void createConnection();    //本函数在modbuswnd对象创建的时候调用，目的是建立调试控制界面与串口传输类信号的调控机制

    void resetRxCount() { m_rxCount = 0; emit sgRxCountChanged(); } //复位接收包计数
    void resetTxCount() { m_txCount = 0; emit sgTxCountChanged(); } //复位发送包计数
    void resetErrorCount() { m_errorCount = 0; emit sgErrorCountChanged(); }    //复位错误包统计计数
    void addRxCount() { m_rxCount++; emit sgRxCountChanged(); } //接收包统计加一
    void addTxCount() { m_txCount++; emit sgTxCountChanged(); } //发送包统计加一
    void addErrorCount() { m_errorCount++; emit sgErrorCountChanged(); }    //错误包统计加一


    int onParseData(QStringList &parsedData, QByteArray data);  //解析下位机数据准备在表格中呈现

    QByteArray trimReadedRegData(QByteArray data); //把从下位机读过来的关键数据以QByteArray返回
    QByteArray trimReadedCoilData(QByteArray data); //把从下位机读过来的关键数据以QByteArray返回
    void readSettings();    //本函数读取设置文件中的关于串口波特率的最基本默认设置

    void closeEvent(QCloseEvent * event);   //当窗口要关闭时我们要做的收尾工作
    void addDataToTxRxResultModel(QStringList info); //本函数把QstringList info信息挂在m_modelTxRxResult二位一体表格上去了
    void addDataToTxPktQueueModel(QStringList parsedData);

    QByteArray makeRTUFrame(QByteArray slaveAddr, QByteArray functionCode, QByteArray startAddr,
                                       QByteArray numOfRegister, QByteArray byteCount, const QByteArray writeData);
    QByteArray makeWEDMFrame(QByteArray functionCode, QByteArray startAddr, const QByteArray writeData);

public slots:

    void onPortConnected();
    void onPortDisconnected();
    void onPortResponseTimeout();

    void onBtnOpenClicked();
    void onBtnCloseClicked();
    void onRecvedData(QByteArray data);
    void onSendedData(QByteArray data);
    void onRecvedErrorData(QByteArray data);

    void onCmbComportTextChanged(QString str);
    quint32 onCmbBaudrateTextChanged(QString str);
    quint32 onCmbDataBitsTextChanged(QString str);
    quint32 onCmbParityTextChanged(QString str);
    quint32 onCmbStopBitsTextChanged(QString str);

    void onLineDecimalChanged();
    void onLineHexChanged();

    void onCmbCommModeCurrentTextChanged(QString str);
    void onCmbFunctionCurrentTextChanged(QString str);
    void onCmbSendCountTextChanged(QString str);
    void onChkAutoSendToggled(bool checked);    //开启自动发射功能
    void onChkIgnoreAckToggled(bool checked);
    void onLineModbusTimeoutChanged(QString str);
    void onLineModbusEditingFinished();

    void onBtnManualSendClicked();  //手动发送待发送列表的当前某个帧
    void onBtnScreenClearClicked();
    void removeModelTxRxResult();
    void onBtnRefreshClicked();

    void onRxCountChanged();
    void onTxCountChanged();
    void onErrorCountChanged();
    void onT15IntervalChanged();
    void onT35IntervalChanged();

    void onBtnResultFileSaveClicked();

    void btnTxQueueAddClicked()       ;
    void btnTxQueueRemoveClicked()    ;
    void btnTxQueueUpClicked()        ;
    void btnTxQueueDownClicked()      ;
    void btnTxQueueFileOpenClicked()  ;
    void btnTxqueueFileSaveClicked()  ;

    void btnCheckSumClicked();
    void btnCRC16Clicked();
    void btnCRC32Clicked(); 

    void onLineAscToHexAscInputClicked();
    void onLineAscToHexHexInputClicked();
    void onModelTxPktQueueDataChanged(QModelIndex topLeft, QModelIndex bottomRight);





    void onTimerAutoSendTimeout();  //定时时间到了，准备发送待发送列表上的帧
    void onModelTxResultRowInserted(const QModelIndex &parent, int first, int last);
    void onViewTxQueueDataSelectionCurrentRowChanged(const QModelIndex &current, const QModelIndex &previous);
    void sendModelTxPktQueue(int index );
    void onReadyEntered();

signals:
    void sgRxCountChanged();
    void sgTxCountChanged();
    void sgErrorCountChanged();
    void sgConnected(QString str);
    void sgDisconnected(QString str);

    void sgRecvedRegData(QByteArray rdata);//把从下位机读过来的寄存器数据以信号形式发送
    void sgRecvedColData(QByteArray cdata);//把从下位机读过来的线圈数据以信号形式发送
private:
    SerialPort*             m_port;
    QStandardItemModel*     m_modelTxPktQueue;  //待发送表格项的数据模型与QTableView二位一体
    QStandardItemModel*     m_modelTxRxResult;  //发送及接受状况表格项的数据模型与QTableView二位一体
    quint64                 m_rxCount;  //已接受多少Rx数据帧统计
    quint64                 m_txCount;  //已发送多少Tx数据帧统计
    quint64                 m_errorCount;   //接受多少报错统计
    quint64                 m_txRxResultMaxRow;
    QThread*                m_threadForSerial;  //线程对象指针，这个线程以后要跑串口类的

    //发送：从QTimer* m_timerAutoSend -> onChkAutoSendToggled()->onTimerAutoSendTimeout() -> onReadyEntered() -> sendModelTxPktQueue() -> invokeMethod(m_port, "sendData", ... )
    QTimer*                 m_timerAutoSend;    //自动间隔发送的定时器,是发送的肇始端

    Ui::ModbusWnd *ui;
};

#endif // MODBUSWND_H
